package hu.bme.domain;

import hu.bme.domain.Icon.Type;

import java.util.ArrayList;
import java.util.List;

public class Table {
	private List<Icon> table;
	
	public enum EndState{WIN,DRAW, GO_ON};
	
	public enum Direction{UP,UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT};

	private User winner;
	private User currentUser;

	private int size;

	public Table() {
		super();
		currentUser = new User();
	}

	public Table(int n) {
		this();
		table = new ArrayList<Icon>();
		this.size = n;

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				Icon icon;
				if ((j + i) % 2 == 1) {
					icon = new Icon(new Position().setX(j).setY(i));
				} else {
					icon = new Icon(new Position().setX(j).setY(i));
				}
				table.add(icon);
			}
		}
	}

	public void setIconByPosition(Position position) {
		
		Icon oldIcon = new Icon(position);
		Icon newIcon = iconFactory(position);

		if(table.contains(oldIcon))
			setItem(oldIcon, newIcon);
		
		
		
	}
	
	public void setItem(Icon oldItem, Icon newItem) {
	    int itemIndex = table.indexOf(oldItem);
	    if (itemIndex != -1) {
	        table.set(itemIndex, newItem);
	    }
	}

	// FEKTORI
	private Icon iconFactory(Position p) {
		if (currentUser.getId().equals("CROSS")) {
			return new Cross(p);
		} else {
			return new Circle(p);
		}
	}
	
	public EndState checkEndConditions(Position pos, int moves)
	{
		final int toWin = 5;
		
		if(getNumberOfSameIconAtDirection(pos, Direction.UP) + getNumberOfSameIconAtDirection(pos, Direction.DOWN) >= (toWin - 1))
			return EndState.WIN;
		
		if(getNumberOfSameIconAtDirection(pos, Direction.UP_LEFT) + getNumberOfSameIconAtDirection(pos, Direction.DOWN_RIGHT) >= (toWin - 1))
			return EndState.WIN;
		
		if(getNumberOfSameIconAtDirection(pos, Direction.UP_RIGHT) + getNumberOfSameIconAtDirection(pos, Direction.DOWN_LEFT) >= (toWin - 1))
			return EndState.WIN;
		
		if(getNumberOfSameIconAtDirection(pos, Direction.LEFT) + getNumberOfSameIconAtDirection(pos, Direction.RIGHT) >= (toWin - 1))
			return EndState.WIN;
		
		if(moves == (size * size))
			return EndState.DRAW;
		
		return EndState.GO_ON;
	}
	
	//does not count himself into the result
	private int getNumberOfSameIconAtDirection(Position position, Direction direction)
	{
		int x = position.getX();
		int y = position.getY();
		
		//current icon type (X or O)
		Type iconType = table.get(size * y + x).getType();
		
		int numberOfSameIcon = 0;
		
		int i = 1;
		switch (direction) {
		case UP:
			while(y - i >= 0 && table.get(size * (y - i) + x).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case UP_RIGHT:
			while(y - i >= 0 && x + i < size  && table.get(size * (y - i) + x + i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}		
			break;
		case RIGHT:
			while(x + i < size && table.get(size * y + x + i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case DOWN_RIGHT:
			while(y + i < size && x + i < size  && table.get(size * (y + i) + x + i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case DOWN:
			while(y + i < size && table.get(size * (y + i) + x).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case DOWN_LEFT:
			while(y + i <= size && x - i >= 0  && table.get(size * (y + i) + x - i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case LEFT:
			while(x - i >= 0 && table.get(size * y + x - i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
		case UP_LEFT:
			while(y - i >= 0 && x - i >= 0  && table.get(size * (y - i) + x - i).getType().equals(iconType))
			{
				numberOfSameIcon++;
				i++;
			}
			break;
	

		default:
			break;
		}
		
		return numberOfSameIcon;
	}

	public User getCurrentRound() {
		return currentUser;
	}

	public void setCurrentRound(User currentRound) {
		this.currentUser = currentRound;
	}

	public User getWinner() {
		return winner;
	}

	public void setWinner(User winner) {
		this.winner = winner;
	}

	public List<Icon> getTable() {
		return table;
	}

	public void setTable(List<Icon> table) {
		this.table = table;
	}

	public void processRound(Icon icon) {
		// TODO
	}

	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

}
